# React & Spring Boot ์ฐ๋
React์ Spring Boot์ ์ฐ๋์ ์ฐ์ตํด๋ณด์
Front-end : React
Back-end : Spring Boot
์คํ๋ง ๋ถํธ๋ฅผ ํตํด ์๋ฒ API ์ญํ ์ ๊ตฌ์ถํ๊ณ , UI ๋ก์ง์ React์์ ๋ด๋น ( React๋ ์ปดํฌ๋ํธํ๊ฐ ์๋์ด์์ด์ ์ฌ์ฌ์ฉ์ฑ์ด ์ข๊ณ , ์๋ง์ ์คํ์์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํ์ฉ ์ฅ์ ์กด์ฌ)
# ๊ฐ๋ฐ ํ๊ฒฝ๋๊ตฌ (์ค์นํ ๊ฒ)
- VSCode : ํ์ฅ ํ๋ก๊ทธ๋จ์ผ๋ก Java Extension Pack, Spring Boot Extension Pack ์ค์น
(๋ฉ๋ด-๊ธฐ๋ณธ์ค์ -์ค์ ์์ JDK ๊ฒ์ ํ 'setting.json์์ ํธ์ง'์ ๋ค์ด๊ฐ
java.home
์ผ๋ก jdk ๊ฒฝ๋ก ๋ฃ์ด์ฃผ๊ธฐ)
"java.home": "C:\\Program Files\\Java\\jdk1.8.0_181" // ์์ ์ ๊ฒฝ๋ก์ ๋ง์ถ๊ธฐ
Node.js : 10.16.0
JDK(8 ์ด์)
# Spring Boot ์น ํ๋ก์ ํธ ์์ฑ
VSCode์์
ctrl-shift-p
์ ๋ ฅ ํ, spring ๊ฒ์ํด์Spring Initalizr: Generate Maven Project Spring
์ ํํ๋ก์ ํธ๋ฅผ ์ ํํ๋ฉด ๋์ค๋ ์ง๋ฌธ์ ์๋์ ๊ฐ์ด ์ ๋ ฅ
- ์ธ์ด : Java
- Group Id : no4gift
- Artifact Id : test
- Spring boot version : 2.1.6
- Dependency : DevTools, Spring Web Starter Web ๊ฒ์ ํ Selected
ํ๋ก์ ํธ๋ฅผ ์ ์ฅํ ํด๋๋ฅผ ์ง์ ํ๋ฉด Spring Boot ํ๋ก์ ํธ๊ฐ ์ค์น๋๋ค!
์ผ๋จ React๋ฅผ ๋ถ์ด๊ธฐ ์ ์, Spring Boot ์์ฒด๋ก ์ ๊ตฌ๋๋๋์ง ์งํํด๋ณด์
JSP์ JSTL์ ์ฌ์ฉํ๊ธฐ ์ํด ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ถ๊ฐํ๋ค. pom.xml์ dependencies ํ๊ทธ ์์ ์ถ๊ฐํ์
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<scope>provided</scope>
</dependency>
์ด์ ์๋ฒ๋ฅผ ๊ตฌ๋ํด๋ณด์
VSCode์์ ํฐ๋ฏธ๋ ์ฐฝ์ ์ด๊ณ .\mvnw spring-boot:run
์ ์
๋ ฅํ๋ฉด ์๋ฒ๊ฐ ์คํ๋๋ ๋ชจ์ต์ ํ์ธํ ์ ์๋ค.
๋ง์ฝ ์๋์ ๊ฐ์ ์๋ฌ๊ฐ ๋ฐ์ํ๋ฉด?
***************************
APPLICATION FAILED TO START
***************************
Description:
The Tomcat connector configured to listen on port 8080 failed to start. The port may already be in use or the connector may be misconfigured.
8080ํฌํธ๋ฅผ ์ด๋ฏธ ์ฌ์ฉ ์ค์ด๋ผ ๊ตฌ๋์ด ๋์ง ์๋ ๊ฒ์ด๋ค.
cmd์ฐฝ์ ๊ด๋ฆฌ์ ๊ถํ์ผ๋ก ์ด๊ณ ์๋์ ๊ฐ์ด ์งํํ์
netstat -ao |find /i "listening"
ํ์ฌ ๊ตฌ๋ ์ค์ธ ํฌํธ๋ค์ด ๋์จ๋ค. ์ด์ค์ 8080 ํฌํธ๋ฅผ ํ์ธํ ์ ์์ ๊ฒ์ด๋ค.
๊ฐ์ฅ ์ค๋ฅธ์ชฝ์ ๋์ค๋ ์ซ์๊ฐ PID๋ฒํธ๋ค. ์ด๊ฑธ kill ํด์ค์ผ ํ๋ค.
taskkill /f /im [pid๋ฒํธ]
๋ค์ ์๋ฒ๋ฅผ ๊ตฌ๋ํด๋ณด๋ฉด ์๋์ฒ๋ผ ์ ๋์ํ๋ ๊ฒ์ ํ์ธํ ์ ์๋ค!
# React ํ๊ฒฝ ์ถ๊ฐํ๊ธฐ
ํฐ๋ฏธ๋์ ํ๋ ๋ ์ถ๊ฐ๋ก ์ด๊ณ , npm init
์ ์
๋ ฅํด pakage.json ํ์ผ์ด ์๊ธฐ๋๋ก ํ์
๋์ค๋ ์ง๋ฌธ๋ค์ ๋ชจ๋ enter ๋๋ฅด๊ณ ๋์ด๊ฐ๋ ๊ด์ฐฎ์
์ด์ React ๊ฐ๋ฐ์ ํ์ํ ์์กด ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ค์นํ๋ค.
npm i react react-dom
npm i @babel/core @babel/preset-env @babel/preset-react babel-loader css-loader style-loader webpack webpack-cli -D
create-react-app์ผ๋ก ํ๋ฒ์ ์ค์น๋ ๊ฐ๋ฅํจ
# webpack ์ค์ ํ๊ธฐ
webpack์ ํตํด react ๊ฐ๋ฐ ์ ์๋ฐ์คํฌ๋ฆฝํธ ๊ธฐ๋ฅ๊ณผ jsp์ ํฌํจํ .js ํ์ผ์ ๋ง๋ค ์ ์๋ค.
ํ๋ก์ ํธ ๋ฃจํธ ๊ฒฝ๋ก์ webpack.config.js ํ์ผ์ ๋ง๋ค๊ณ ์๋ ์ฝ๋๋ฅผ ๋ถ์ฌ๋ฃ๊ธฐ
var path = require('path');
module.exports = {
context: path.resolve(__dirname, 'src/main/jsx'),
entry: {
main: './MainPage.jsx',
page1: './Page1Page.jsx'
},
devtool: 'sourcemaps',
cache: true,
output: {
path: __dirname,
filename: './src/main/webapp/js/react/[name].bundle.js'
},
mode: 'none',
module: {
rules: [ {
test: /\.jsx?$/,
exclude: /(node_modules)/,
use: {
loader: 'babel-loader',
options: {
presets: [ '@babel/preset-env', '@babel/preset-react' ]
}
}
}, {
test: /\.css$/,
use: [ 'style-loader', 'css-loader' ]
} ]
}
};
- ์ฝ๋ ๋ด์ฉ
React ์์ค ๊ฒฝ๋ก๋ฅผ src/main/jsx๋ก ์ค์
MainPage์ Page1Page.jsx ๋น๋
๋น๋ ๊ฒฐ๊ณผ js ํ์ผ๋ค์ src/main/webapp/js/react ์๋ [ํ์ด์ง ์ด๋ฆ].bundle.js๋ก ๋์
# ์๋ฒ ์ฝ๋ ๊ฐ๋ฐํ๊ธฐ
VSCode์์ ํจํค์ง ์์ MyController.java๋ผ๋ ํด๋์ค ํ์ผ์ ๋ง๋ ๋ค.
package no4gift.test;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@Controller
public class MyController {
@GetMapping("/{name}.html")
public String page(@PathVariable String name, Model model) {
model.addAttribute("pageName", name);
return "page";
}
}
์ถ๊ฐ๋ก src/main์๋ค๊ฐ webapp ํด๋๋ฅผ ๋ง๋ค์
webapp ํด๋ ์์ jsp ํด๋์ css ํด๋๋ฅผ ์์ฑํ๋ค.
๊ทธ๋ฆฌ๊ณ jsp์ css ํ์ผ์ ํ๋์ฉ ๋ฃ์ด๋ณด์
# src/main/webapp/jsp/page.jsp
<%@ page language="java" contentType="text/html; charset=utf-8"%>
<!doctype html>
<html>
<head>
<title>${pageName}</title>
</head>
<body>
<div id="root"></div>
<script src="/js/react/${pageName}.bundle.js"></script>
</body>
</html>
# src/main/webapp/css/custom.css
.main {
font-size: 24px; border-bottom: solid 1px black;
}
.page1 {
font-size: 14px; background-color: yellow;
}
# ํด๋ผ์ด์ธํธ ์ฝ๋ ๊ฐ๋ฐํ๊ธฐ
์ด์ ์นํ์ด์ง์ ๋ณด์ฌ์ค JSX ํ์ผ์ ๋ง๋ค์ด๋ณด์
src/main์ jsx ํด๋๋ฅผ ๋ง๋ค๊ณ MainPage.jsx์ Page1Page.jsx 2๊ฐ์ง jsx ํ์ผ์ ๋ง๋ค์๋ค.
# src/main/jsx/MainPage.jsx
import '../webapp/css/custom.css';
import React from 'react';
import ReactDOM from 'react-dom';
class MainPage extends React.Component {
render() {
return <div className="main">no4gift ๋ฉ์ธ ํ์ด์ง</div>;
}
}
ReactDOM.render(<MainPage/>, document.getElementById('root'));
# src/main/jsx/Page1Page.jsx
import '../webapp/css/custom.css';
import React from 'react';
import ReactDOM from 'react-dom';
class Page1Page extends React.Component {
render() {
return <div className="page1">no4gift์ Page1 ํ์ด์ง</div>;
}
}
ReactDOM.render(<Page1Page/>, document.getElementById('root'));
์๊น ์์ฑํ cssํ์ผ์ importํ ๊ฒ์ ๋ณผ ์ ์๋๋ฐ, css ์ ์ฉ ๋ฐฉ์์ ์ด๋ฐ์๋ ์ฌ๋ฌ๊ฐ์ง ๋ฐฉ๋ฒ์ด ์๋ค.
์ด์ ์ฐ๋ฆฌ๊ฐ ๋ง๋ ํด๋ผ์ด์ธํธ ํ์ด์ง๋ฅผ ์๋ฒ ๊ตฌ๋ ํ ๋ณผ ์ ์๋๋ก ๋น๋์์ผ์ผ ํ๋ค!
# ํด๋ผ์ด์ธํธ ์คํฌ๋ฆฝํธ ๋น๋์ํค๊ธฐ
jsx ํ์ผ์ ์์ ํ ๋๋ง๋ค ์๋์ผ๋ก ์ง์์ ๋น๋๋ฅผ ์์ผ์ฃผ๋ ๊ฒ์ด ํ์ํ๋ค.
์ด๋ webpack์ watch ๋ช ๋ น์ ํตํด ๊ฐ๋ฅํ๋๋ก ๋ง๋ค ์ ์๋ค.
VSCode ํฐ๋ฏธ๋์์ ์๋์ ๊ฐ์ด ์ ๋ ฅํ์
node_modules\.bin\webpack --watch -d
-d๋ ๊ฐ๋ฐ์
-p๋ ์ด์์
ํฐ๋ฏธ๋ ํ๋ฉด์ ๋ณด๋ฉด, webpack.config.js
์์ ์ฐ๋ฆฌ๊ฐ ์ค์ ํ๋๋ก ์ ์์ ์ผ๋ก ๋น๋๋๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
src/main/webapp/js/react ์๋์ ์ฐ๋ฆฌ๊ฐ ๋ง๋ ๋ ํ์ด์ง์ ๋ํ bundle.js ํ์ผ์ด ์์ฑ๋์์ผ๋ฉด ์ ๋๋ก ๋ ๊ฒ์ด๋ค.
์๋ฒ ๊ตฌ๋์ด๋, ๋ฒ๋ค๋ง์ด๋ ๋ช
๋ น์ด ์
๋ ฅ์ด ์๋นํ ๊ธธ๊ธฐ ๋๋ฌธ์ ๊ท์ฐฎ๋คใ
ใ
pakage.json
์ script์ ๋ฑ๋กํด๋๋ฉด ๊ฐํธํ๊ฒ ๋น๋๊ณผ ์๋ฒ ์คํ์ ์งํํ ์ ์๋ค.
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "set JAVA_HOME=C:\\Program Files\\Java\\jdk1.8.0_181&&mvnw spring-boot:run",
"watch": "node_modules\\.bin\\webpack --watch -d"
},
์ด์ฒ๋ผ start์ watch๋ฅผ ๋ฑ๋กํด๋๋ ๊ฒ!
start์ jdk๊ฒฝ๋ก๋ ๊ฐ์ ์์ ์ ๊ฒฝ๋ก๋ฅผ ์ ๋ ฅํด์ผํ๋ค.
์ด์ ์ฐ๋ฆฌ๋ ๋น๋๋ npm run watch
๋ก, ์คํ๋ง ๋ถํธ ์๋ฒ ์คํ์ npm run start
๋ก ์งํํ ์ ์๋ค~
๋น๋๊ฐ ์ด๋ฃจ์ด์ก๊ธฐ ๋๋ฌธ์ ์ฐ๋ฆฌ๊ฐ ๋ง๋ ํ์ด์ง๋ฅผ ํ์ธํด๋ณผ ์ ์๋ค.
ํด๋น ๊ฒฝ๋ก๋ก ๋ค์ด๊ฐ๋ฉด ์ฐ๋ฆฌ๊ฐ jsxํ์ผ๋ก ์์ฑํ ๋ชจ์ต์ด ์ ๋๋ก ์ถ๋ ฅ๋๋ค.
MainPage : http://localhost:8080/main.html
Page1Page : http://localhost:8080/page1.html
์ฌ๊ธฐ๊น์ง ์งํํ ํ๋ก์ ํธ ๊ฒฝ๋ก
์ด์ ๊ฐ์ ๊ณผ์ ์ ํ ๋๋ก ๊ตฌํํ ์นํ์ด์ง๋ค์ ์์ฑํด ๋๊ฐ๋ฉด ๋๋ค.
์ด์ React์ Spring Boot ์ฐ๋ํด์ ํ๊ฒฝ ์ค์ ํ๊ธฐ ๋!